﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using System.Diagnostics;
using System.Threading;
using System.Messaging;

namespace Sinacor.OMM.Util
{
#if !TRACE || !DEBUG

    public class TraceWriter
    {
        private const string CLSID = "A72AE7BA-08D5-4209-8774-358F80580AD1";

        private string _folderName;
        private string _fileName;
        private bool _closing = false;
        private bool _optionalTraceEnabled = false;
        private MessageQueue _msmq;

        public TraceWriter(string folderName, string fileName, string clsId)
        {
            //Essa classe não deve ser instanciada diretamente, chame a mesma a partir do Tracer.GetInstance()
            if (clsId != CLSID)
                throw new InvalidOperationException("TraceWriter não pode ser instanciado diretamente, use Tracer.GetInstance()");

            this._folderName = folderName;
            this._fileName = fileName;

            if (_folderName.StartsWith(@"\"))
                _folderName = _folderName.Substring(1, _folderName.Length - 1);

            if (_folderName.Substring(1, 1) == @":")
                _folderName = _folderName.Substring(3, _folderName.Length - 3);

            if (_folderName.EndsWith(@"\"))
                _folderName = _folderName.Substring(0, _folderName.Length - 1);

            //
            string path = String.Empty;

            try
            {
                //
                path = UtilConfigurationManager.DumperConfiguration.MessageRepository.ConnectionInformation[Configuration.Repository.RepositoryPropertiesConstants.ConnectionString];

                // if (!Int32.TryParse(UtilConfigurationManager.DumperConfiguration.MessageRepository.ConnectionInformation[Configuration.Repository.RepositoryPropertiesConstants.QueueMessageLimit], out queueMessageLimit))
                //     queueMessageLimit = int.MaxValue;

                //if (!long.TryParse(UtilConfigurationManager.DumperConfiguration.MessageRepository.ConnectionInformation[Configuration.Repository.RepositoryPropertiesConstants.QueueBytesLimit], out queueBytesLimit))
                //    queueBytesLimit = long.MaxValue;

                _msmq = new MessageQueue(path);

            }
            catch (MessageQueueException mqex)
            {
                EventLog.WriteEntry("TraceWriter", "Não conseguiu se conectar ao MSMQ " + path);
                EventLog.WriteEntry("TraceWriter", mqex.Message);
                EventLog.WriteEntry("TraceWriter", mqex.StackTrace);
            }
            catch (Exception ex)
            {
                EventLog.WriteEntry("TraceWriter", "Erro não definido no constructor de TraceWriter");
                EventLog.WriteEntry("TraceWriter", ex.Message);
                EventLog.WriteEntry("TraceWriter", ex.StackTrace);
            }
        }

        public void Trace(string expression)
        {
            Trace(expression, TraceType.Mandatory);
        }

        public void Trace(string expression, TraceType traceType)
        {
            if (!_closing)
            {
                if (_msmq != null && expression != null)
                {
                    Message msg = new Message();
                    msg.Formatter = new BinaryMessageFormatter();
                    msg.Label = "3";
                    msg.Body = MontaDumpPoisoned(expression);

                    if (traceType == TraceType.Optional)
                    {
                        if (_optionalTraceEnabled)
                        {
                            _msmq.Send(msg);
                        }
                    }
                    else
                    {
                        _msmq.Send(msg);
                    }
                }
            }
        }

        public string MontaDumpPoisoned(string expression)
        {
            return DateTime.Now.Ticks.ToString() + "|" + _folderName + "|" + _fileName + "|" + expression;
        }

        public bool OptionalTraceEnabled
        {
            get { return _optionalTraceEnabled; }
            set { _optionalTraceEnabled = value; }
        }

        public void Close()
        {
            _closing = true;
            _msmq.Dispose();
        }
    }
#endif


#if TRACE && DEBUG
    public class TraceWriter
    {
        private const string CLSID = "A72AE7BA-08D5-4209-8774-358F80580AD1";

        private string _path;
        private string _fileName;
        private bool _disposing = false;
        private Mutex _mutex = new Mutex();
        private bool _optionalTraceEnabled = false;
        private FileStream fs;

        public TraceWriter(string folderName, string fileName, string clsId)
        {
            //Essa classe não deve ser instanciada diretamente, chame a mesma a partir do Tracer.GetInstance()
            if (clsId != CLSID)
                throw new InvalidOperationException("TraceWriter não pode ser instanciado diretamente, use Tracer.GetInstance()");

            try
            {
                this._path = folderName;
                this._fileName = fileName;

                if (_path.StartsWith(@"\"))
                    _path = _path.Substring(1, _path.Length - 1);
                if (!String.IsNullOrEmpty(_path.Trim()))
                {
                    if (_path.Substring(1, 1) == @":")
                        _path = _path.Substring(3, _path.Length - 3);
                }


                _path = @"C:\Sinacor Receptor Mensagens\Trace\" + _path;

                if (!Directory.Exists(_path))
                    Directory.CreateDirectory(_path);

                if (!_path.EndsWith(@"\"))
                    _path += @"\";

                if (!_fileName.EndsWith(@".log"))
                {
                    _fileName += DateTime.Now.ToString(" yyyy-dd-MM");
                    _fileName += @".log";
                }
                else // Se termina com .log
                {
                    _fileName = _fileName.Substring(0, _fileName.Length - 4);
                    _fileName += DateTime.Now.ToString(" yyyy-dd-MM");
                    _fileName += @".log";
                }

                if (_fileName.Contains(":"))
                    _fileName = _fileName.Replace(":", "-");

                if (IsFileOpen(Path.Combine(_path, _fileName)))
                {
                    _fileName += " Concurrency Safe " + DateTime.Now.ToString("hhMMssffff") + ".log";
                    if (IsFileOpen(Path.Combine(_path, _fileName)))
                    {
                        _fileName += " Concurrency Safe " + DateTime.Now.ToString("hhMMssffff") + " " + Process.GetCurrentProcess().Id + Thread.CurrentThread.ManagedThreadId + ".log";
                    }
                }

                fs = new FileStream(_path + _fileName, FileMode.Append);
            }
            catch (System.IO.IOException ex)
            {
                LogEventViewer("OMM", "TraceWriter", ex.StackTrace, EventLogEntryType.Error, 9999);
            }
            catch (Exception ex)
            {
                LogEventViewer("OMM", "TraceWriter", ex.StackTrace, EventLogEntryType.Error, 9999);
            }
        }

        public void Trace(string expression)
        {
            try
            {
                if (!_disposing && fs != null)
                {
                    if (_mutex != null)
                        _mutex.WaitOne();

                    lock (fs)
                    {
                        expression = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.ffff") + " -> " + expression + "\r\n";
                        try
                        {
                            fs.Write(Encoding.Default.GetBytes(expression), 0, expression.Length);
                            fs.Flush();
                        }
                        catch (Exception)
                        {
                            try
                            {
                                FileStream fsBackup = new FileStream(_path + "lost" + _fileName, FileMode.OpenOrCreate);
                                fsBackup.Write(Encoding.Default.GetBytes(expression), 0, expression.Length);
                                fsBackup.Flush();
                                fsBackup.Close();
                                fsBackup.Dispose();
                            }
                            catch (Exception ex)
                            {
                                LogEventViewer("OMM", "TraceWriter", expression + "\r\n" + ex.StackTrace, EventLogEntryType.Error, 9999);
                            }
                        }
                    }

                    if (_mutex != null)
                        _mutex.ReleaseMutex();
                }
            }
            catch (Exception ex)
            {
                LogEventViewer("OMM", "TraceWriter", expression + "\r\n" + ex.StackTrace, EventLogEntryType.Error, 9999);
            }

        }

        public void Trace(string expression, TraceType traceType)
        {
            if (traceType == TraceType.Optional)
            {
                if (_optionalTraceEnabled)
                {
                    Trace(expression);
                }
            }
        }

        public void Close()
        {
            if (!_disposing)
            {
                try
                {
                    _disposing = true;

                    if (fs != null)
                    {
                        if (_mutex != null)
                            _mutex.WaitOne();

                        lock (fs)
                        {
                            fs.Flush();
                            fs.Close();
                            fs.Dispose();
                        }

                        if (_mutex != null)
                        {
                            _mutex.ReleaseMutex();
                            _mutex.Close();
                            _mutex = null;
                        }
                    }
                }
                catch (Exception ex)
                {
                    LogEventViewer("OMM", "TraceWriter", ex.StackTrace, EventLogEntryType.Error, 9999);
                }
            }
        }

        public void LogEventViewer(string sSource, string sLog, string sEvent, EventLogEntryType eType, int eventid)
        {
            try
            {
                if (!EventLog.SourceExists(sSource))
                    EventLog.CreateEventSource(sSource, sLog);

                EventLog.WriteEntry(sSource, sEvent);
                EventLog.WriteEntry(sSource, sEvent, eType, eventid);
            }
            catch (Exception ex)
            {
                try
                {
                    if (!EventLog.SourceExists(sSource))
                        EventLog.CreateEventSource("TraceWriter", "Falha geral");

                    EventLog.WriteEntry("TraceWriter", ex.Message);
                    EventLog.WriteEntry("TraceWriter", ex.StackTrace, EventLogEntryType.Error, 200);
                }
                catch (Exception)
                { }
            }
        }

        public bool OptionalTraceEnabled
        {
            get { return _optionalTraceEnabled; }
            set { _optionalTraceEnabled = value; }
        }

        private bool IsFileOpen(string filePath)
        {
            bool fileOpened = false;

            try
            {
                System.IO.FileStream fs = System.IO.File.OpenWrite(filePath);
                fs.Close();
                fs.Dispose();
            }
            catch (System.IO.IOException ex)
            {
                fileOpened = true;
            }
            catch (Exception ex)
            {
                fileOpened = true;
            }

            return fileOpened;
        }

    }
#endif

}
